package cn.devmgr.tutorial;

import cn.devmgr.tutorial.utils.Browser;
import cn.devmgr.tutorial.utils.DataItem;
import cn.devmgr.tutorial.utils.JiVariantUtil;
import org.jinterop.dcom.common.JIException;
import org.jinterop.dcom.core.JIVariant;
import org.openscada.opc.lib.common.AlreadyConnectedException;
import org.openscada.opc.lib.common.ConnectionInformation;
import org.openscada.opc.lib.common.NotConnectedException;
import org.openscada.opc.lib.da.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.net.UnknownHostException;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

@CrossOrigin
@RestController
@RequestMapping("/opc")
public class OPCServicesController {

    @Autowired
    OPCConfig opcConfig;

    private ConnectionInformation connectionInformation(){
        final ConnectionInformation ci = new ConnectionInformation();
        ci.setHost(opcConfig.getHost());         // 电脑IP
        ci.setDomain("");                  // 域，为空就行
        ci.setUser(opcConfig.getUser());             // 电脑上自己建好的用户名
        ci.setPassword(opcConfig.getPassword());          // 用户名的密码
        // 使用KEPServer的配置
        ci.setClsid(opcConfig.getClsId());
        return ci;
    }

    @GetMapping("items")
    public List<String> getAll() {
        final ConnectionInformation ci = new ConnectionInformation();
        ci.setHost(opcConfig.getHost());         // 电脑IP
        ci.setDomain("");                  // 域，为空就行
        ci.setUser(opcConfig.getUser());             // 电脑上自己建好的用户名
        ci.setPassword(opcConfig.getPassword());          // 用户名的密码
        // 使用KEPServer的配置
        ci.setClsid(opcConfig.getClsId()); // KEPServer的注册表ID，可以在“组件服务”里看到
        //final String itemId = "u.u.u";    // 项的名字按实际，没有实际PLC，用的模拟器：simulator
        //final String itemId = "通道 1.设备 1.标记 1";

        // 启动服务
        final Server server = new Server(ci, Executors.newSingleThreadScheduledExecutor());

        try {
            // 连接到服务
            server.connect();
            Collection<String> itemIds = server.getFlatBrowser().browse();
            List<String> result = itemIds.parallelStream().collect(Collectors.toList());
            // add sync access, poll every 500 ms，启动一个同步的access用来读取地址上的值，线程池每500ms读值一次
            // 这个是用来循环读值的，只读一次值不用这样
            server.dispose();
            return result;
        } catch (final JIException e) {
            System.out.println(e.getMessage());
            System.out.println(String.format("%08X: %s", e.getErrorCode(), server.getErrorMessage(e.getErrorCode())));
        } catch (AlreadyConnectedException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } finally {
            server.dispose();
        }
        return null;
    }

    @GetMapping("dataitems")
    public List<DataItem> getDataItemsFromServer() throws AlreadyConnectedException, JIException, UnknownHostException {
        final Server server = new Server(this.connectionInformation(),Executors.newSingleThreadScheduledExecutor());
        server.connect();
        List<DataItem> dataItems = Browser.readSync(server);
        server.dispose();
        return dataItems;
    }

    @PutMapping("item")
    public DataItem getDataItemById(@RequestBody DataItem dataItem) throws Exception {
        final Server server = new Server(this.connectionInformation(),Executors.newSingleThreadScheduledExecutor());
        server.connect();
        List<DataItem> dataItems = Browser.readSync(server);
        DataItem res = dataItems.parallelStream().filter(item->item.getItemId().equals(dataItem.getItemId())).findFirst().get();
        server.dispose();
        return res;
    }

    @PutMapping("write/bool")
    public DataItem changOpcBool(@RequestBody DataItem dataItem){
        final Server server = new Server(this.connectionInformation(), Executors.newSingleThreadScheduledExecutor());

        try {
            // 连接到服务
            server.connect();
            final Group group = server.addGroup("test");
            // Add a new item to the group，
            // 将一个item加入到组，item名字就是MatrikonOPC Server或者KEPServer上面建的项的名字比如：u.u.TAG1，PLC.S7-300.TAG1
            final Item item = group.addItem(dataItem.getItemId());
            //根据type做数据转型处理
            final JIVariant value = new JIVariant((boolean)dataItem.getValue());
            int result = item.write(value);
            DataItem res = JiVariantUtil.parseValue(item.getId(),item.read(false));
            server.dispose();
            return res;
        } catch (final JIException e) {
            System.out.println(e.getMessage());
            System.out.println(String.format("%08X: %s", e.getErrorCode(), server.getErrorMessage(e.getErrorCode())));
        } catch (AlreadyConnectedException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (AddFailedException e) {
            e.printStackTrace();
        } catch (NotConnectedException e) {
            e.printStackTrace();
        } catch (DuplicateGroupException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            server.dispose();
        }
        return null;
    }

    @PutMapping("write/double")
    public DataItem changOpcDouble(@RequestBody DataItem dataItem){
        final Server server = new Server(this.connectionInformation(), Executors.newSingleThreadScheduledExecutor());
        try {
            // 连接到服务
            server.connect();
            final Group group = server.addGroup("test");
            // Add a new item to the group，
            // 将一个item加入到组，item名字就是MatrikonOPC Server或者KEPServer上面建的项的名字比如：u.u.TAG1，PLC.S7-300.TAG1
            final Item item = group.addItem(dataItem.getItemId());
            //根据type做数据转型处理

            final JIVariant value = new JIVariant(Double.valueOf(dataItem.getValue().toString()));
            int result = item.write(value);
            DataItem res = JiVariantUtil.parseValue(item.getId(),item.read(false));
            server.dispose();
            return res;
        } catch (final JIException e) {
            System.out.println(e.getMessage());
            System.out.println(String.format("%08X: %s", e.getErrorCode(), server.getErrorMessage(e.getErrorCode())));
        } catch (AlreadyConnectedException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (AddFailedException e) {
            e.printStackTrace();
        } catch (NotConnectedException e) {
            e.printStackTrace();
        } catch (DuplicateGroupException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            server.dispose();
        }
        return null;
    }
}
